import json
import re
import unicodedata
import uuid
from copy import deepcopy
from datetime import datetime
from urllib.parse import unquote

import win32api
import win32print
from flask import request
from flask_restful import marshal
from flask_sqlalchemy.model import camel_to_snake_case


class Response:
    @classmethod
    def success(cls, data=None):
        response_data = data
        if data is not None:
            response_data = obj_underline2hump(data)
        return json.dumps({
            'success': True,
            'data': response_data,
        }, ensure_ascii=False)

    @classmethod
    def error(cls, message: str = None):
        return json.dumps({
            'success': False,
            'message': str(message)
        }, ensure_ascii=False)


def get_file_name(headers, prefix='.pdf'):
    filename = ''
    if 'Content-Disposition' in headers and headers.get('Content-Disposition'):
        disposition_list = headers.get('Content-Disposition').split('?')
        if len(disposition_list) > 1:
            if disposition_list[1].strip().starwith('filename='):
                filename = disposition_list[1].split('=')
                if filename.__len__() > 1:
                    filename = unquote(filename[1])
    if not filename:
        return str(uuid.uuid4()) + prefix
    return filename


#  BaseQuery对象字典无用项清理
def model_dict_clear(mod_dict):
    if '_sa_instance_state' in mod_dict:
        del mod_dict['_sa_instance_state']
    return mod_dict


def to_camel(key):
    arr = filter(None, key.lower().split('_'))
    res = ''
    j = 0
    for i in arr:
        if j == 0:
            res = i
        else:
            res = res + i[0].upper() + i[1:]
        j += 1
    return res


def random_filename():
    return str(uuid.uuid4())


def df_to_json(df, orient='split'):
    df_json = df.to_json(orient=orient, force_ascii=False)
    data = json.loads(df_json)
    # return data
    columns = data.get('columns')
    # index = data.get('columns')
    data = data.get('data')
    item_list = []
    for i, item in enumerate(data):
        t = {}
        for col in columns:
            t[col] = item[i]
        item_list.append(t)

    return item_list


def camel_json_to_line(params):
    item = {}
    for attr, value in params.items():
        item[camel_to_line(attr)] = value
    return item


def line_json_to_camel(params):
    if params is None:
        return {}
    params = deepcopy(params)
    item = {}
    for attr, value in params.items():
        if type(value) == datetime:
            value = datetime.strftime(value, "%Y-%m-%d %H:%M:%S")
        if "_" in attr:
            item[to_camel(attr)] = value
        else:
            item[attr] = value
    return item


# 驼峰转下划线
def camel_to_line(listx):
    listy = listx[0]
    for i in range(1, len(listx)):
        # listx[i] 直接copy 或 先加'_'再copy
        if listx[i].isupper() and not listx[i - 1].isupper():  # 加'_',当前为大写，前一个字母为小写
            listy += '_'
            listy += listx[i]
        elif listx[i].isupper() and listx[i - 1].isupper() and listx[i + 1].islower():
            # 加'_',当前为大写，前一个字母为小写
            listy += '_'
            listy += listx[i]
        else:
            listy += listx[i]
    return listy.lower()


def transform_list_to_tree(items, parent_name='parentId', start_parent='NULL'):
    def get_rank(elem):
        return elem['rank']

    def get_children(parent_node=None):
        children = []
        items.sort(key=get_rank)
        if parent_node is None:
            for item in items:
                if item[parent_name] == '0' or item[parent_name] == start_parent:
                    children.append(item)
        else:
            for item in items:
                if item[parent_name] == parent_node['id']:
                    children.append(item)
            parent_node['children'] = children
        if children.__len__():
            for item in children:
                get_children(item)
        return children

    tree = get_children()
    return tree


def deserialize_dict(data, model):
    if type(data) == list:
        return [dict(marshal(item, model.__deserialize_fields__())) for item in data]
    return dict(marshal(data, model.__deserialize_fields__()))


def serialize_fetchall(list, deserialize=True):
    non_update_list = ['last_edited_ip', 'last_edited_time', 'last_edited_user', 'created_user', 'created_time']
    return_list = []
    if list:
        for each in list:
            inner_dict = {}
            each = dict(each)
            for k, v in each.items():
                if k in non_update_list:
                    continue
                elif k == 'birthday' and v:
                    inner_dict[k] = v.strftime("%Y-%m-%d")
                elif isinstance(v, datetime):
                    inner_dict[k] = v.strftime('%Y-%m-%d %H:%M:%S')
                else:
                    inner_dict[k] = v
            if deserialize:
                return_list.append(line_json_to_camel(inner_dict))
            else:
                return_list.append(inner_dict)
    return return_list


def get_ids(ids):
    if len(ids) == 0:
        return "'0'"
    return ",".join(["'{}'".format(key) for key in ids])


def get_line_list(items):
    return [dict(item) for item in items]


def get_camel_list(items):
    return [line_json_to_camel(dict(item)) for item in items]


def hump2underline(hump_str):
    """
    驼峰形式字符串转成下划线形式
    :param hump_str: 驼峰形式字符串
    :return: 字母全小写的下划线形式字符串
    """
    # 匹配正则，匹配小写字母和大写字母的分界位置
    p = re.compile(r'([a-z]|\d)([A-Z])')
    # 这里第二个参数使用了正则分组的后向引用
    return re.sub(p, r'\1_\2', hump_str).lower()


def underline2hump(underline_str):
    """
    下划线形式字符串转成驼峰形式
    :param underline_str: 下划线形式字符串
    :return: 驼峰形式字符串
    """
    # 这里re.sub()函数第二个替换参数用到了一个匿名回调函数，回调函数的参数x为一个匹配对象，返回值为一个处理后的字符串
    return re.sub(r'(_\w)', lambda x: x.group(1)[1].upper(), underline_str)


def json_hump2underline(hump_json_str):
    """
    把一个json字符串中的所有字段名都从驼峰形式替换成下划线形式。
    注意点：因为考虑到json可能具有多层嵌套的复杂结构，所以这里直接采用正则文本替换的方式进行处理，而不是采用把json转成字典再进行处理的方式
    :param hump_json_str: 字段名为驼峰形式的json字符串
    :return: 字段名为下划线形式的json字符串
    """
    # 从json字符串中匹配字段名的正则
    # 注：这里的字段名只考虑由英文字母、数字、下划线组成
    attr_ptn = re.compile(r'"\s*(\w+)\s*"\s*:')
    # 使用hump2underline函数作为re.sub函数第二个参数的回调函数
    return re.sub(attr_ptn, lambda x: '"' + hump2underline(x.group(1)) + '" :', hump_json_str)


def obj_underline2hump(obj):
    if isinstance(obj, list):
        return [obj_underline2hump(o) for o in obj]
    item = {}
    for key in list(obj.keys()):
        item[underline2hump(key)] = obj[key]
    return item


def curtime():
    return datetime.now().strftime('%Y-%m-%d %H:%M:%S')


def slugify(string):
    string = re.sub(r'[^\w\s-]', '',
                    unicodedata.normalize('NFKD', string.strip()))
    return re.sub(r'[-\s]+', '-', string).lower()


def title_case(string):
    return camel_to_snake_case(string).replace('_', ' ').title()


def pluralize(name):
    if name.endswith('y'):
        # right replace 'y' with 'ies'
        return 'ies'.join(name.rsplit('y', 1))
    elif name.endswith('s'):
        return f'{name}es'
    return f'{name}s'


def getRequestData():
    if request.data == b'':
        return {}
    return json.loads(request.data.decode('utf-8'))


def print_file(filename):
    win32api.ShellExecute(
        0,
        'print',
        filename,
        '"%s "' % win32print.GetDefaultPrinter(),
        '.',
        0
    )
